/*
 * ali_mqtt_task.c
 * Copyright (C) 2020 2020-12-23 20:23 kalipy <kalipy@debian>
 *
 * Distributed under terms of the MIT license.
 */

#include "ali_mqtt_task.h"
#include "los_sys.h"
#include "los_task.h"
#include "los_memory.h"
#include "los_base.h"
#include "ali_mqtt.h"
#include "usart3.h"
#include "wifi.h"
#include "main.h"//extern:r_flag和s_flag和g_doGetMux
#include "los_mux.h"
#include "led.h"

#define LED1_IN_STA HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)

void ali_mqtt_Task(void *arg)
{
    LOS_TaskDelay(15*1000);//等待esp8266任务运行完成，不然ali_mqtt_Task在esp8266任务还没起来就会开始运行，不知道为什么，改优先级也没用，不用延时也可以，可以用消息队列来同步
    AliIoT_Parameter_Init();	    //初始化连接阿里云IoT平台MQTT服务器的参数	
    link_to_ali_mqttserver(5000);
}


void link_to_ali_mqttserver(int timeout)
{
    AliIoT_Parameter_Init();	    //初始化连接阿里云IoT平台MQTT服务器的参数	
    while(1)                        //主循环
    {		
        /*--------------------------------------------------------------------*/
        /*   Connect_flag=1同服务器建立了连接,我们可以发布数据和接收推送了    */
        /*--------------------------------------------------------------------*/
        if(Connect_flag==1){    
            /*-------------------------------------------------------------*/
            /*                     处理发送缓冲区数据                      */
            /*-------------------------------------------------------------*/
            if(MQTT_TxDataOutPtr != MQTT_TxDataInPtr){                //if成立的话，说明发送缓冲区有数据了
                //3种情况可进入if
                //第1种：0x10 连接报文
                //第2种：0x82 订阅报文，且ConnectPack_flag置位，表示连接报文成功
                //第3种：SubcribePack_flag置位，说明连接和订阅均成功，其他报文可发
                if((MQTT_TxDataOutPtr[2]==0x10)||((MQTT_TxDataOutPtr[2]==0x82)&&(ConnectPack_flag==1))||(SubcribePack_flag==1)){    
                    u3_printf("send data:0x%x\r\n",MQTT_TxDataOutPtr[2]);  //串口提示信息
                    MQTT_TxData(MQTT_TxDataOutPtr);                       //发送数据
                    MQTT_TxDataOutPtr += TBUFF_UNIT;                      //指针下移
                    if(MQTT_TxDataOutPtr==MQTT_TxDataEndPtr)              //如果指针到缓冲区尾部了
                        MQTT_TxDataOutPtr = MQTT_TxDataBuf[0];            //指针归位到缓冲区开头
                } 				
            }//处理发送缓冲区数据的else if分支结尾

            /*-------------------------------------------------------------*/
            /*                     处理接收缓冲区数据                      */
            /*-------------------------------------------------------------*/
            if(MQTT_RxDataOutPtr != MQTT_RxDataInPtr){  //if成立的话，说明接收缓冲区有数据了														
                u3_printf("recieved data:");
                /*-----------------------------------------------------*/
                /*                    处理CONNACK报文                  */
                /*-----------------------------------------------------*/				
                //if判断，如果第一个字节是0x20，表示收到的是CONNACK报文
                //接着我们要判断第4个字节，看看CONNECT报文是否成功
                if(MQTT_RxDataOutPtr[2]==0x20){             			
                    switch(MQTT_RxDataOutPtr[5]){					
                        case 0x00 : u3_printf("CONNECT baowen success\r\n");                            //串口输出信息	
                                    ConnectPack_flag = 1;                                        //CONNECT报文成功，订阅报文可发
                                    break;                                                       //跳出分支case 0x00                                              
                        case 0x01 : u3_printf("link reject,unsupport mqtt banben,ready reboot wifi\r\n");     //串口输出信息
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接
                                    break;                                                       //跳出分支case 0x01   
                        case 0x02 : u3_printf("link reject,bu hege de client biaosifu,reboot\r\n"); //串口输出信息
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接
                                    break;                                                       //跳出分支case 0x02 
                        case 0x03 : u3_printf("link reject,server bukeyon,reboot\r\n");         //串口输出信息
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接
                                    break;                                                       //跳出分支case 0x03
                        case 0x04 : u3_printf("link reject,username or pwd error,reboot\r\n");   //串口输出信息
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接						
                                    break;                                                       //跳出分支case 0x04
                        case 0x05 : u3_printf("link reject,wei sou quan,reboot\r\n");               //串口输出信息
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接						
                                    break;                                                       //跳出分支case 0x05 		
                        default   : u3_printf("link reject,unknown status,reboot\r\n");             //串口输出信息 
                                    Connect_flag = 0;                                            //Connect_flag置零，重启连接					
                                    break;                                                       //跳出分支case default 								
                    }				
                }			
                //if判断，第一个字节是0x90，表示收到的是SUBACK报文
                //接着我们要判断订阅回复，看看是不是成功
                else if(MQTT_RxDataOutPtr[2]==0x90){ 
                    switch(MQTT_RxDataOutPtr[6]){					
                        case 0x00 :
                        case 0x01 : u3_printf("subcribe success\r\n");            //串口输出信息
                                    SubcribePack_flag = 1;                //SubcribePack_flag置1，表示订阅报文成功，其他报文可发送
                                    Ping_flag = 0;                        //Ping_flag清零
                                    LED1_State();                         //判断开关状态，并发布给服务器  
                                    break;                                //跳出分支                                             
                        default   : u3_printf("subcribe fail,ready reboot wifi\r\n");  //串口输出信息 
                                    Connect_flag = 0;                     //Connect_flag置零，重启连接
                                    break;                                //跳出分支 								
                    }					
                }
                //if判断，第一个字节是0xD0，表示收到的是PINGRESP报文
                else if(MQTT_RxDataOutPtr[2]==0xD0){ 
                    u3_printf("PING baowen huifu\r\n"); 		  //串口输出信息 
                    if(Ping_flag==1){                     //如果Ping_flag=1，表示第一次发送
                        Ping_flag = 0;    				  //要清除Ping_flag标志
                    }else if(Ping_flag>1){ 				  //如果Ping_flag>1，表示是多次发送了，而且是2s间隔的快速发送
                        Ping_flag = 0;     				  //要清除Ping_flag标志
                    }				
                }	
                //if判断，如果第一个字节是0x30，表示收到的是服务器发来的推送数据
                //我们要提取控制命令
                else if((MQTT_RxDataOutPtr[2]==0x30)){ 
                    u3_printf("server waiting tuison of level0\r\n"); 		   //串口输出信息 
                    MQTT_DealPushdata_Qs0(MQTT_RxDataOutPtr);  //处理等级0推送数据
                }				

                MQTT_RxDataOutPtr +=RBUFF_UNIT;                     //指针下移
                if(MQTT_RxDataOutPtr==MQTT_RxDataEndPtr)            //如果指针到缓冲区尾部了
                    MQTT_RxDataOutPtr = MQTT_RxDataBuf[0];          //指针归位到缓冲区开头                        
            }//处理接收缓冲区数据的else if分支结尾

            /*-------------------------------------------------------------*/
            /*                     处理命令缓冲区数据                      */
            /*-------------------------------------------------------------*/
            if(MQTT_CMDOutPtr != MQTT_CMDInPtr){                             //if成立的话，说明命令缓冲区有数据了			       
                u3_printf("cmd:%s\r\n",&MQTT_CMDOutPtr[2]);                 //串口输出信息
                if(strstr((char *)MQTT_CMDOutPtr+2,"\"params\":{\"allPowerstate\":1")){	       //如果搜索到"params":{"PowerSwitch":1}说明服务器下发打开开关1	
                    u3_printf("led1 = 0\r\n");                 //串口输出信息
                    //LED1_ON;                                                                   //打开LED1
                    drv_led_on(led1);
                    LED1_State();                                                              //判断开关状态，并发布给服务器  
                }else if(strstr((char *)MQTT_CMDOutPtr+2,"\"params\":{\"allPowerstate\":0")){   //如果搜索到"params":{"PowerSwitch":0}说明服务器下发关闭开关1
                    //LED1_OFF;                                                                  //关闭LED1
                    u3_printf("led1 = 1\r\n");                 //串口输出信息
                    drv_led_off(led1);
                    LED1_State();                                                              //判断开关状态，并发布给服务器  
                }
                MQTT_CMDOutPtr += CBUFF_UNIT;                             	 //指针下移
                if(MQTT_CMDOutPtr==MQTT_CMDEndPtr)           	             //如果指针到缓冲区尾部了
                    MQTT_CMDOutPtr = MQTT_CMDBuf[0];          	             //指针归位到缓冲区开头				
            }//处理命令缓冲区数据的else if分支结尾
        }//Connect_flag=1的if分支的结尾

        /*--------------------------------------------------------------------*/
        /*      Connect_flag=0同服务器断开了连接,我们要重启连接服务器         */
        /*--------------------------------------------------------------------*/
        else{ 
            u3_printf("need link to server\r\n");                 //串口输出信息
            WiFi_RxCounter=0;                                //WiFi接收数据量变量清零                        
            memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);          //清空WiFi接收缓冲区 
            if(esp8266_connect_server(mqtt_ServerIP, mqtt_ServerPort, 5000)==0){   			     //如果WiFi连接云服务器函数返回0，表示正确，进入if
                u3_printf("build TCP link success\r\n");            //串口输出信息
                Connect_flag = 1;                            //Connect_flag置1，表示连接成功	
                WiFi_RxCounter=0;                            //WiFi接收数据量变量清零                        
                memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);      //清空WiFi接收缓冲区 
                MQTT_Buff_Init();                            //初始化发送缓冲区                    
            }				
        }
    }
}

int ali_mqtt_task_start(void)
{
    UINT32 uwRet = 0;
    UINT32 uwTask;
    TSK_INIT_PARAM_S stInitParam;

    stInitParam.pfnTaskEntry = ali_mqtt_Task;
    stInitParam.usTaskPrio = 9;
    stInitParam.uwStackSize = 0x400;
    stInitParam.pcName = "ali_mqtt";
    //stInitParam.uwResved = LOS_TASK_STATUS_DETACHED;//自删除任务，运行完一次，即删除
    uwRet = LOS_TaskCreate(&uwTask, &stInitParam);
    if(uwRet != LOS_OK)
    {
        u3_printf("ali_mqtt_Task create failed\r\n");
        return uwRet;
    }
    u3_printf("ali_mqtt_Task create ok\r\n");
}

/*-------------------------------------------------*/
/*函数名：判断开关1状态，并发布给服务器            */
/*参  数：无                                       */
/*返回值：无                                       */
/*-------------------------------------------------*/
void LED1_State(void)
{
    char temp[TBUFF_UNIT];                   //定义一个临时缓冲区

    if(LED1_IN_STA) sprintf(temp,"{\"method\":\"thing.event.property.post\",\"id\":\"203302322\",\"params\":{\"allPowerstate\":0},\"version\":\"1.0.0\"}");  //如果LED1是高电平，说明是熄灭状态，需要回复关闭状态给服务器
    else            sprintf(temp,"{\"method\":\"thing.event.property.post\",\"id\":\"203302322\",\"params\":{\"allPowerstate\":1},\"version\":\"1.0.0\"}");  //如果LED1是低电平，说明是点亮状态，需要回复打开状态给服务器
    MQTT_PublishQs0(P_TOPIC_NAME,temp,strlen(temp));   //添加数据，发布给服务器		
}
